using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using EMall.Application;
using EMall.Domain;
using EMall.Events;
using EMall.Middlewares;
using EMall.Query;
using EMall.Uow;
using IdentityModel;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Serilog;
using System.Data;
using System.Reflection;

namespace EMall.AuthServer
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var allAssemblies = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "EMall*.dll")
               .Select(o => Assembly.Load(AssemblyName.GetAssemblyName(o))).ToList();
            var builder = WebApplication.CreateBuilder(args);
            builder.Host.UseSerilog((hostBuilderContext, serviceProvider, loggerConfiguration) =>
            {
                loggerConfiguration.ReadFrom.Configuration(hostBuilderContext.Configuration);
            });
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>(containerBuilder =>
                {
                    var assemblies = allAssemblies.ToArray();
                    #region EventBus
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IEventBus)) && t.Name.EndsWith("EventBus"))
                    .AsImplementedInterfaces().InstancePerLifetimeScope();
                    #endregion
                    #region UnitOfWorks
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IUnitOfWork)) && t.Name.EndsWith("UnitOfWork"))
                    .AsImplementedInterfaces().InstancePerLifetimeScope();
                    #endregion
                    #region Interceptors
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IInterceptor)) && t.Name.EndsWith("Interceptor"));
                    #endregion
                    #region QueryServices
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IQueryService)) && t.Name.EndsWith("QueryService"))
                    .AsImplementedInterfaces().InstancePerLifetimeScope();
                    #endregion
                    #region ApplicationServices
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && t.GetInterfaces().Contains(typeof(IApplicationService)) && t.Name.EndsWith("AppService"))
                    .AsImplementedInterfaces().InstancePerLifetimeScope()
                    .EnableInterfaceInterceptors().InterceptedBy(typeof(UnitOfWorkInterceptor))
                    .PropertiesAutowired();
                    #endregion
                    #region Repositories
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IRepository)) && t.Name.EndsWith("Repository"))
                    .AsImplementedInterfaces()
                    .InstancePerLifetimeScope();
                    #endregion
                    #region DomainServices 
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IDomainService)) && t.Name.EndsWith("Manager"));
                    #endregion
                });
            builder.Services.AddControllersWithViews();
            builder.Services.AddCors(options =>
            {
                var origins = builder.Configuration.GetSection("Cors").Value!.Split(",");
                options.AddDefaultPolicy(config =>
                {
                    config
                    .WithOrigins(origins)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
                });
            });
            builder.Services.AddDbContext<AuthServerDbContext>(options =>
            {
                options.UseSqlite(builder.Configuration.GetConnectionString("Sqlite"),
                    builder => builder.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name));
                //options.UseMySql(
                //    builder.Configuration.GetConnectionString("Default"),
                //    MySqlServerVersion.LatestSupportedServerVersion,
                //    builder => builder.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name));
            });
            builder.Services.AddIdentity<User, Role>(options =>
            {
                options.Password.RequiredUniqueChars = 6;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequireDigit = false;

                options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject;
                options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.Name;
                options.ClaimsIdentity.RoleClaimType = JwtClaimTypes.Role;
                options.ClaimsIdentity.EmailClaimType = JwtClaimTypes.Email;
            })
                .AddClaimsPrincipalFactory<IdentityServerUserClaimsPrincipalFactory>()
                .AddUserStore<UserRepository>()
                .AddRoleStore<RoleRepository>();
            builder.Services.AddIdentityServer()
                .AddAspNetIdentity<User>()
                .AddDeveloperSigningCredential()
                //.AddProfileService<IdentityServerProfileService>()
                //.AddResourceOwnerValidator<IdentityServerResourceOwnerPasswordValidator>()
                .AddResourceStore<IdentityServerResourceStore>()
                .AddClientStore<IdentityServerClientStore>();
            builder.Services.AddAutoMapper(allAssemblies);
            var app = builder.Build();
            app.UseCors();
            app.UseRequestLogging();
            app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
            app.UseStaticFiles();
            app.UseIdentityServer();
            app.UseAuthorization();
            app.MapDefaultControllerRoute();
            app.Run();
        }
    }
}
